package com.jianggujin.redis.dialog;

import java.awt.BorderLayout;
import java.util.regex.Pattern;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

import com.jianggujin.redis.config.ConnectionConfig;
import com.jianggujin.redis.util.MessageUtils;

import redis.clients.jedis.Jedis;

public class ConnectionSettingsDialog extends AbstractDialog {
    private JTextField nameField;
    private JTextField hostField;
    private JTextField portField;
    private JTextField authField;
    private JTextField keysGlobStylePatternField;
    private JTextField namespaceSeparatorField;
    private JTextField connectionTimeoutField;
    private JTextField soTimeoutField;

    private JButton testBtn;
    private JButton saveBtn;
    private JButton cancelBtn;

    private ConnectionConfig currentConfig = null;

    private ConnectionSettingsDialog(ConnectionsDialog parent) {
        super(parent);

    }

    private void initCenter() {
        Box center = Box.createVerticalBox();
        center.add(Box.createVerticalStrut(10));

        Box nameBox = Box.createHorizontalBox();
        nameBox.add(Box.createHorizontalStrut(10));
        nameBox.add(new JLabel("Name:"));
        nameBox.add(Box.createHorizontalStrut(10));
        nameField = new JTextField("New Connection");
        nameBox.add(nameField);
        nameBox.add(Box.createHorizontalStrut(10));
        center.add(nameBox);

        center.add(Box.createVerticalStrut(10));

        Box connectStringBox = Box.createHorizontalBox();
        connectStringBox.add(Box.createHorizontalStrut(10));
        connectStringBox.add(new JLabel("Host:"));
        connectStringBox.add(Box.createHorizontalStrut(10));
        hostField = new JTextField("localhost");
        connectStringBox.add(hostField);
        connectStringBox.add(Box.createHorizontalStrut(10));
        center.add(connectStringBox);

        center.add(Box.createVerticalStrut(10));

        Box portBox = Box.createHorizontalBox();
        portBox.add(Box.createHorizontalStrut(10));
        portBox.add(new JLabel("Port:"));
        portBox.add(Box.createHorizontalStrut(10));
        portField = new JTextField();
        portField.setDocument(new RegexPlainDocument("[1-9]\\d*"));
        portField.setText("6379");
        portBox.add(portField);
        portBox.add(Box.createHorizontalStrut(10));
        center.add(portBox);

        center.add(Box.createVerticalStrut(10));

        Box authBox = Box.createHorizontalBox();
        authBox.add(Box.createHorizontalStrut(10));
        authBox.add(new JLabel("Auth:"));
        authBox.add(Box.createHorizontalStrut(10));
        authField = new JTextField();
        authBox.add(authField);
        authBox.add(Box.createHorizontalStrut(10));
        center.add(authBox);

        center.add(Box.createVerticalStrut(10));

        Box keysGlobStylePatternBox = Box.createHorizontalBox();
        keysGlobStylePatternBox.add(Box.createHorizontalStrut(10));
        keysGlobStylePatternBox.add(new JLabel("KeysGlobStylePattern:"));
        keysGlobStylePatternBox.add(Box.createHorizontalStrut(10));
        keysGlobStylePatternField = new JTextField("*");
        keysGlobStylePatternBox.add(keysGlobStylePatternField);
        keysGlobStylePatternBox.add(Box.createHorizontalStrut(10));
        center.add(keysGlobStylePatternBox);

        center.add(Box.createVerticalStrut(10));

        Box namespaceSeparatorBox = Box.createHorizontalBox();
        namespaceSeparatorBox.add(Box.createHorizontalStrut(10));
        namespaceSeparatorBox.add(new JLabel("NamespaceSeparator:"));
        namespaceSeparatorBox.add(Box.createHorizontalStrut(10));
        namespaceSeparatorField = new JTextField(":");
        namespaceSeparatorField.setDocument(new RegexPlainDocument("[:]"));
        namespaceSeparatorField.setText(":");
        namespaceSeparatorBox.add(namespaceSeparatorField);
        namespaceSeparatorBox.add(Box.createHorizontalStrut(10));
        center.add(namespaceSeparatorBox);

        center.add(Box.createVerticalStrut(10));

        Box connectionTimeoutBox = Box.createHorizontalBox();
        connectionTimeoutBox.add(Box.createHorizontalStrut(10));
        connectionTimeoutBox.add(new JLabel("ConnectionTimeout:"));
        connectionTimeoutBox.add(Box.createHorizontalStrut(10));
        connectionTimeoutField = new JTextField();
        connectionTimeoutField.setDocument(new RegexPlainDocument("[1-9]\\d*"));
        connectionTimeoutField.setText("30");
        connectionTimeoutBox.add(connectionTimeoutField);
        connectionTimeoutBox.add(Box.createHorizontalStrut(10));
        center.add(connectionTimeoutBox);

        center.add(Box.createVerticalStrut(10));

        Box soTimeoutBox = Box.createHorizontalBox();
        soTimeoutBox.add(Box.createHorizontalStrut(10));
        soTimeoutBox.add(new JLabel("SoTimeout:"));
        soTimeoutBox.add(Box.createHorizontalStrut(10));
        soTimeoutField = new JTextField("30");
        soTimeoutField.setDocument(new RegexPlainDocument("[1-9]\\d*"));
        soTimeoutField.setText("30");
        soTimeoutBox.add(soTimeoutField);
        soTimeoutBox.add(Box.createHorizontalStrut(10));
        center.add(soTimeoutBox);

        this.add(center);
    }

    private void initConnectionConfig(ConnectionConfig configItem) {
        if (configItem != null) {
            this.nameField.setText(configItem.getName());
            this.hostField.setText(configItem.getHost());
            this.portField.setText(configItem.getPort() + "");
            this.authField.setText(configItem.getAuth());
            this.keysGlobStylePatternField.setText(configItem.getKeysGlobStylePattern());
            this.namespaceSeparatorField.setText(configItem.getNamespaceSeparator() + "");
            this.connectionTimeoutField.setText(configItem.getConnectionTimeout() + "");
            this.soTimeoutField.setText(configItem.getSoTimeout() + "");
        }
    }

    private void initBottom() {
        Box buttom = Box.createHorizontalBox();
        buttom.add(Box.createHorizontalStrut(10));
        testBtn = new JButton("Test");
        testBtn.addActionListener(e -> handleTest());
        buttom.add(testBtn);
        buttom.add(Box.createHorizontalGlue());
        saveBtn = new JButton("Save");
        saveBtn.addActionListener(e -> handleSave());
        cancelBtn = new JButton("Cancel");
        cancelBtn.addActionListener(e -> dispose());
        buttom.add(saveBtn);
        buttom.add(cancelBtn);
        buttom.add(Box.createHorizontalStrut(10));
        this.add(buttom, BorderLayout.SOUTH);
    }

    @Override
    protected void initComponent() {
        initCenter();
        initBottom();
    }

    @Override
    protected void initDialog() {
        setTitle("Connection Settings");
        setSize(500, 430);
        this.setResizable(false);
        super.initDialog();
    }

    private ConnectionConfig createConnectionConfig() {
        String name = this.nameField.getText();
        if (name.length() == 0) {
            MessageUtils.showWarningMessage(this, "Name required");
            return null;
        }
        String host = this.hostField.getText();
        if (host.length() == 0) {
            MessageUtils.showWarningMessage(this, "Host required");
            return null;
        }
        String port = this.portField.getText();
        if (port.length() == 0) {
            MessageUtils.showWarningMessage(this, "Port required");
            return null;
        }
        String auth = this.authField.getText();
        String keysGlobStylePattern = this.keysGlobStylePatternField.getText();
        String namespaceSeparator = this.namespaceSeparatorField.getText();
        String connectionTimeout = this.connectionTimeoutField.getText();
        if (connectionTimeout.length() == 0) {
            MessageUtils.showWarningMessage(this, "ConnectionTimeout required");
            return null;
        }
        String soTimeout = this.soTimeoutField.getText();
        if (soTimeout.length() == 0) {
            MessageUtils.showWarningMessage(this, "SoTimeout required");
            return null;
        }

        ConnectionConfig config = new ConnectionConfig();
        config.setName(name);
        config.setHost(host);
        config.setPort(Integer.parseInt(port));
        config.setAuth(auth);
        config.setKeysGlobStylePattern(keysGlobStylePattern);
        config.setNamespaceSeparator(namespaceSeparator.charAt(0));
        config.setConnectionTimeout(Integer.parseInt(connectionTimeout));
        config.setSoTimeout(Integer.parseInt(soTimeout));
        return config;
    }

    /**
     * 保存
     */
    private void handleTest() {
        ConnectionConfig config = createConnectionConfig();
        if (config == null) {
            return;
        }
        Jedis client = null;
        try {
            client = new Jedis(config.getHost(), config.getPort(), config.getConnectionTimeout(),
                    config.getSoTimeout());
            client.connect();
            if (client != null && (config.getAuth() != null && config.getAuth().length() > 0)) {
                client.auth(config.getAuth());
            }
            if (client.isConnected()) {
                MessageUtils.showInfoMessage(this, "Success");
            } else {
                MessageUtils.showErrorMessage(this, "Fail");
            }
        } catch (Exception e) {
            MessageUtils.showErrorMessage(this, "Error:" + e.getMessage());
        } finally {
            if (client != null) {
                client.close();
            }
        }
    }

    /**
     * 保存
     */
    private void handleSave() {
        ConnectionConfig config = createConnectionConfig();
        if (config == null) {
            return;
        }
        currentConfig = config;
        this.dispose();
    }

    public static ConnectionConfig connectionSetting(ConnectionsDialog parent, ConnectionConfig config) {
        ConnectionSettingsDialog dialog = new ConnectionSettingsDialog(parent);
        dialog.initConnectionConfig(config);
        dialog.setVisible(true);
        return dialog.currentConfig;
    }

    private static class RegexPlainDocument extends PlainDocument {
        private Pattern pattern;

        public RegexPlainDocument(String regex) {
            pattern = Pattern.compile(regex);
        }

        @Override
        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
            if (pattern.matcher(str).matches()) {
                super.insertString(offs, str, a);
            }
        }
    }
}
